home *** CD-ROM | disk | FTP | other *** search
/ Info-Mac 3 / Info_Mac_1994-01.iso / Development / General / GCC 1.37.1r15 / GCC.MPW / aux-output.c next >
Text File  |  1993-01-04  |  49KB  |  1,746 lines

  1. /* Subroutines for insn-output.c for Macintosh.
  2.    Several routines are taken from the generic 68k aux-output,
  3.    the rest of this file is original code.
  4.    Copyright (C) 1987 Free Software Foundation, Inc.
  5.    Copyright (C) 1989, 1990 Apple Computer, Inc.
  6.  
  7. This file is part of GNU CC.
  8.  
  9. GNU CC is free software; you can redistribute it and/or modify
  10. it under the terms of the GNU General Public License as published by
  11. the Free Software Foundation; either version 1, or (at your option)
  12. any later version.
  13.  
  14. GNU CC is distributed in the hope that it will be useful,
  15. but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17. GNU General Public License for more details.
  18.  
  19. You should have received a copy of the GNU General Public License
  20. along with GNU CC; see the file COPYING.  If not, write to
  21. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  22.  
  23. #include <stdio.h>
  24.  
  25. int globalize_this;
  26.  
  27. /* Size varies according to cmd option. */
  28.  
  29. int long_double_type_size;
  30.  
  31. /* Index into this array by (register number >> 3) to find the
  32.    smallest class which contains that register.  */
  33. enum reg_class regno_reg_class[]
  34.   = { DATA_REGS, ADDR_REGS, FP_REGS };
  35.  
  36. static rtx find_addr_reg ();
  37.  
  38. #include "tree.h"
  39.  
  40. rtx
  41. function_arg( CUMULATIVE_ARGS *cum, enum machine_mode mode, int named )
  42. {
  43.     int i;
  44.     if ( cum->p == NULL )
  45.         return( 0 );
  46.  
  47.     if(cum->p->params[cum->count]==noreg)
  48.        return( 0 );
  49.     
  50.     if( cum->p->params[cum->count] < 4 )
  51.         i = cum->p->params[cum->count]-1;
  52.     else
  53.         i = cum->p->params[cum->count]+4;
  54.     return( gen_rtx(REG, mode, i ));
  55. }
  56.  
  57. rtx
  58. function_value( tree amode, tree decl )
  59. {
  60.     int i;
  61.     
  62.         if ( (decl == NULL) || ((DECL_PARAM(decl) == NULL) || (DECL_PARAM(decl)->funcreturn==noreg)) )
  63.             if (TARGET_68881 &&  (GET_MODE_CLASS (TYPE_MODE (amode)) == MODE_FLOAT) )
  64.                 return( gen_rtx(REG, TYPE_MODE (amode), 16 ) );
  65.             else
  66.                 return( gen_rtx(REG, TYPE_MODE (amode), 0 ) );
  67.         else {
  68.  
  69.             if( DECL_PARAM(decl)->funcreturn < pa0 )
  70.                 i = DECL_PARAM(decl)->funcreturn-1;
  71.             else
  72.                 i = DECL_PARAM(decl)->funcreturn+4;
  73.         
  74.             return( gen_rtx(REG, TYPE_MODE (amode), i ));
  75.         }
  76.  
  77. }
  78.  
  79. extern int current_function_is_pascal;
  80.  
  81. rtx function_outgoing_value( tree amode, tree decl )
  82. {
  83.     int i;
  84.     
  85.     if( decl != NULL )
  86.         if ( (DECL_PARAM(decl) == NULL) || (DECL_PARAM(decl)->funcreturn==noreg) )
  87.             if( current_function_is_pascal ) {
  88.                 return(  gen_rtx (MEM, TYPE_MODE (amode),
  89.                 gen_rtx (PLUS, Pmode,
  90.                      frame_pointer_rtx,
  91.                      gen_rtx (CONST_INT, VOIDmode, 12345))) );
  92.                 
  93.             }
  94.             else
  95.                 return( function_value( amode, decl ) );
  96.         else {
  97.             if( DECL_PARAM(decl)->funcreturn < pa0 )
  98.                 i = DECL_PARAM(decl)->funcreturn-1;
  99.             else
  100.                 i = DECL_PARAM(decl)->funcreturn+4;
  101.         
  102.             return( gen_rtx(REG, TYPE_MODE (amode), i ));
  103.         }
  104.     else
  105.         return( function_value( amode, decl ) );
  106.  
  107. }
  108.  
  109. function_prologue (fp, size)
  110.      FILE *fp;
  111.      int size;
  112. {
  113.   register int regno;
  114.   char mask[100];
  115.   extern char call_used_regs[];
  116.   extern int frame_pointer_needed;
  117.   int fsize = ((size) + 3) & -4;
  118.  
  119.   if (TARGET_FX30)
  120.     fprintf (fp, "m#start:\n");
  121.   mask[0] = '\0';
  122.   if (frame_pointer_needed)
  123.     {
  124.       if (TARGET_68020 || fsize < 0x8000)
  125.         fprintf (fp, "\tlink a6,#%d\n", -fsize);
  126.       else
  127.     fprintf (fp, "\tlink a6,#0\n\tsub.l #%d,sp\n", fsize);
  128.     }
  129.   for (regno = 16; regno < 24; regno++)
  130.     if (regs_ever_live[regno] && ! call_used_regs[regno])
  131.       {
  132.     strcat(mask, reg_names[regno]);
  133.     strcat(mask, "/");
  134.       }
  135.   if (strlen(mask) > 0)
  136.     {
  137.       mask[strlen(mask)-1] = '\0';
  138.       fprintf (fp, "\tfmovem %s,-(sp)\n", mask);
  139.     }
  140.   mask[0] = '\0';
  141.   for (regno = 0; regno < 16; regno++)
  142.     if (regs_ever_live[regno] && ! call_used_regs[regno] &&
  143.         !(frame_pointer_needed && regno == FRAME_POINTER_REGNUM))
  144.       {
  145.     strcat(mask, reg_names[regno]);
  146.     strcat(mask, "/");
  147.       }
  148.   if (TARGET_FX30)
  149.     {
  150.       strcat(mask, reg_names[13]);
  151.       strcat(mask, "/");
  152.     }
  153.   if (strlen(mask) > 0)
  154.     {
  155.       mask[strlen(mask)-1] = '\0';
  156.       if (index(mask, '/') == 0)
  157.     fprintf (fp, "\tmove.l %s,-(sp)\n", mask);
  158.       else
  159.     fprintf (fp, "\tmovem.l %s,-(sp)\n", mask);
  160.     }
  161.   if (TARGET_FX30)
  162.     {
  163.       fprintf (fp, "\tDC.L $4bfb0170 ; lea -> a5\n");
  164.       fprintf (fp, "\tDC.L _StaticDataArea-m#start-*+2\n");
  165.     }
  166.   /* Hook for tracing has to be called after everything else is set up. */
  167.   if (generate_trace_calls)
  168.     {
  169.       fprintf (fp, "\tIMPORT %%_BP\n");
  170.       fprintf (fp, "\tjsr %%_BP\n");
  171.     }
  172. }
  173.  
  174. /* Function epilogue code restores any saved regs and then returns.  There
  175.    are a number of obscure details and different options that can come up. */
  176.  
  177. /* Note the Macsbug symbol output at the end (see Appendix G of Macsbug
  178.    reference for details). */
  179.  
  180. /* Also note that the pascal function return sequence is cribbed from MPW,
  181.    for no particularly deep reason. */
  182.  
  183. function_epilogue (fp, size)
  184.      FILE *fp;
  185.      int size;
  186. {
  187.   register int regno;
  188.   register int nregs;
  189.   int offset, foffset, fpoffset;
  190.   extern char call_used_regs[];
  191.   extern int current_function_pops_args;
  192.   extern int current_function_args_size;
  193.   extern int current_function_is_pascal;
  194.   extern int frame_pointer_needed;
  195.   int fsize = ((size) + 3) & -4;
  196.   int big = 0;
  197.   char mask[100], fmask[100];
  198.  
  199.   /* Have to generate the trace calls after the return result is set up (by function
  200.      body), but before any state restoration happens. */
  201.   if (generate_trace_calls)
  202.     {
  203.       fprintf (fp, "\tmove.l d0,-(a7)\n");
  204.       fprintf (fp, "\tIMPORT %%_EP\n");
  205.       fprintf (fp, "\tjsr %%_EP\n");
  206.       fprintf (fp, "\tmove.l (a7)+,d0\n");
  207.     }
  208.   /* Now compute which of all the registers has to be restored. */
  209.   mask[0] = '\0'; fmask[0] = '\0';
  210.   nregs = 0;
  211.   for (regno = 16; regno < 24; regno++)
  212.     if (regs_ever_live[regno] && ! call_used_regs[regno])
  213.       { nregs++; strcat(fmask, reg_names[regno]);  strcat(fmask, "/"); }
  214.   foffset = nregs * 12;
  215.   nregs = 0;
  216.   if (frame_pointer_needed) regs_ever_live[FRAME_POINTER_REGNUM] = 0;
  217.   for (regno = 0; regno < 16; regno++)
  218.     if (regs_ever_live[regno] && ! call_used_regs[regno])
  219.       { nregs++; strcat(mask, reg_names[regno]);  strcat(mask, "/"); }
  220.   if (TARGET_FX30)
  221.     { nregs++; strcat(mask, reg_names[13]);  strcat(mask, "/"); }
  222.   offset = foffset + nregs * 4;
  223.   if (offset + fsize >= 0x8000
  224.       && frame_pointer_needed
  225.       && (strlen(mask) > 0 || strlen(fmask) > 0))
  226.     { fprintf (fp, "\tmove.l #%d,a0\n", -fsize);
  227.       fsize = 0, big = 1; }
  228.   if (strlen(mask) > 0) {
  229.     mask[strlen(mask)-1] = '\0';
  230.     if (index(mask, '/') == 0) {
  231.       if (big)
  232.         fprintf (fp, "\tmove.l (-%d,a6,a0:l),%s\n", offset + fsize, mask);
  233.       else if (! frame_pointer_needed)
  234.         fprintf (fp, "\tmove.l (sp)+,%s\n", mask);
  235.       else
  236.         fprintf (fp, "\tmove.l -%d(a6),%s\n", offset + fsize, mask);
  237.     } else {
  238.       if (big)
  239.         fprintf (fp, "\tmovem.l (-%d,a6,a0.l),%s\n", offset + fsize, mask);
  240.       else if (! frame_pointer_needed)
  241.         fprintf (fp, "\tmovem.l (sp)+,%s\n", mask);
  242.       else
  243.         fprintf (fp, "\tmovem.l -%d(a6),%s\n", offset + fsize, mask);
  244.     }
  245.   }
  246.   if (strlen(fmask) > 0) {
  247.     fmask[strlen(fmask)-1] = '\0';
  248.     if (big)
  249.       fprintf (fp, "\tfmovem (-%d,a6,a0.l),%s\n", foffset + fsize, fmask);
  250.     else if (! frame_pointer_needed)
  251.       fprintf (fp, "\tfmovem (sp)+,%s\n", fmask);
  252.     else
  253.       fprintf (fp, "\tfmovem -%d(a6),%s\n", foffset + fsize, fmask);
  254.   }
  255.   if (frame_pointer_needed)
  256.     fprintf (fp, "\tunlk a6\n");
  257. /*  if (current_function_pops_args && current_function_args_size)
  258.     fprintf (fp, "\tDC.W $4e74, %d  ; rtd\n",
  259.          current_function_args_size
  260.          + (current_function_returns_struct ? 4 : 0));
  261.   else */ if (current_function_is_pascal && current_function_args_size > 0)
  262.     fprintf (fp, "\tmovea.l (sp)+,a0\n\tadd.w #%d,sp\n\tjmp (a0)\n",
  263.          current_function_args_size);
  264. /*  else if (current_function_returns_struct)
  265.     fprintf (fp, "\tDC.W $4e74, 4  ; rtd #4\n"); */
  266.   else
  267.     fprintf (fp, "\trts\n");
  268.   if (TARGET_MACSBUG)
  269.     {
  270.       extern char *current_function_name;
  271.       int len = strlen(current_function_name);
  272.  
  273.       if (len < 32)
  274.     fprintf (fp, "\tDC.B $%x, '", 0x80 + len);
  275.       else
  276.     fprintf (fp, "\tDC.B $80, %d, '", len);
  277.       fprintf (fp, "%s", current_function_name);
  278.       fprintf (fp, "'%s\n", ((len < 32) ? ((len+1) & 1 ? ", 0" : "")
  279.                   : ((len+2) & 1 ? ", 0" : "")));
  280.     }
  281.   /* Unconditional, so the "local data length" gets written properly */
  282.   dump_local_strings (fp);
  283. }
  284.  
  285. char *
  286. output_btst (operands, countop, dataop, insn, signpos)
  287.      rtx *operands;
  288.      rtx countop, dataop;
  289.      rtx insn;
  290.      int signpos;
  291. {
  292.   operands[0] = countop;
  293.   operands[1] = dataop;
  294.   if (GET_CODE (countop) == CONST_INT)
  295.     {
  296.       register int count = INTVAL (countop);
  297.       if (count == signpos)
  298.     cc_status.flags = CC_NOT_POSITIVE | CC_Z_IN_NOT_N;
  299.       else
  300.     cc_status.flags = CC_NOT_NEGATIVE | CC_Z_IN_NOT_N;
  301.  
  302.       if (count == 31
  303.       && next_insns_test_no_inequality (insn))
  304.     return "tst.l %1";
  305.       if (count == 15
  306.       && next_insns_test_no_inequality (insn))
  307.     return "tst.w %1";
  308.       if (count == 7
  309.       && next_insns_test_no_inequality (insn))
  310.     return "tst.b %1";
  311.  
  312.       cc_status.flags = CC_NOT_NEGATIVE;
  313.     }
  314.   return "btst %0,%1";
  315. }
  316.  
  317. /* Return the best assembler insn template
  318.    for moving operands[1] into operands[0] as a fullword.  */
  319.  
  320. static char *
  321. singlemove_string (operands)
  322.      rtx *operands;
  323. {
  324.   if (operands[1] != const0_rtx)
  325.     return "move.l %1,%0";
  326.   if (! ADDRESS_REG_P (operands[0]))
  327.     return "clr.l %0";
  328.   return "sub.l %0,%0";
  329. }
  330.  
  331. /* Output assembler code to perform a doubleword move insn
  332.    with operands OPERANDS.  */
  333.  
  334. char *
  335. output_move_double (operands)
  336.      rtx *operands;
  337. {
  338.   enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
  339.   rtx latehalf[2];
  340.   rtx addreg0 = 0, addreg1 = 0;
  341.  
  342.   /* First classify both operands.  */
  343.  
  344.   if (REG_P (operands[0]))
  345.     optype0 = REGOP;
  346.   else if (offsettable_memref_p (operands[0]))
  347.     optype0 = OFFSOP;
  348.   else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
  349.     optype0 = POPOP;
  350.   else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
  351.     optype0 = PUSHOP;
  352.   else if (GET_CODE (operands[0]) == MEM)
  353.     optype0 = MEMOP;
  354.   else
  355.     optype0 = RNDOP;
  356.  
  357.   if (REG_P (operands[1]))
  358.     optype1 = REGOP;
  359.   else if (CONSTANT_P (operands[1])
  360.        || GET_CODE (operands[1]) == CONST_DOUBLE)
  361.     optype1 = CNSTOP;
  362.   else if (offsettable_memref_p (operands[1]))
  363.     optype1 = OFFSOP;
  364.   else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
  365.     optype1 = POPOP;
  366.   else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
  367.     optype1 = PUSHOP;
  368.   else if (GET_CODE (operands[1]) == MEM)
  369.     optype1 = MEMOP;
  370.   else
  371.     optype1 = RNDOP;
  372.  
  373.   /* Check for the cases that the operand constraints are not
  374.      supposed to allow to happen.  Abort if we get one,
  375.      because generating code for these cases is painful.  */
  376.  
  377.   if (optype0 == RNDOP || optype1 == RNDOP)
  378.     abort ();
  379.  
  380.   /* If one operand is decrementing and one is incrementing
  381.      decrement the former register explicitly
  382.      and change that operand into ordinary indexing.  */
  383.  
  384.   if (optype0 == PUSHOP && optype1 == POPOP)
  385.     {
  386.       operands[0] = XEXP (XEXP (operands[0], 0), 0);
  387.       output_asm_insn ("subq.l #8,%0", operands);
  388.       operands[0] = gen_rtx (MEM, DImode, operands[0]);
  389.       optype0 = OFFSOP;
  390.     }
  391.   if (optype0 == POPOP && optype1 == PUSHOP)
  392.     {
  393.       operands[1] = XEXP (XEXP (operands[1], 0), 0);
  394.       output_asm_insn ("subq.l #8,%1", operands);
  395.       operands[1] = gen_rtx (MEM, DImode, operands[1]);
  396.       optype1 = OFFSOP;
  397.     }
  398.  
  399.   /* If an operand is an unoffsettable memory ref, find a register
  400.      we can increment temporarily to make it refer to the second word.  */
  401.  
  402.   if (optype0 == MEMOP)
  403.     addreg0 = find_addr_reg (XEXP (operands[0], 0));
  404.  
  405.   if (optype1 == MEMOP)
  406.     addreg1 = find_addr_reg (XEXP (operands[1], 0));
  407.  
  408.   /* Ok, we can do one word at a time.
  409.      Normally we do the low-numbered word first,
  410.      but if either operand is autodecrementing then we
  411.      do the high-numbered word first.
  412.  
  413.      In either case, set up in LATEHALF the operands to use
  414.      for the high-numbered word and in some cases alter the
  415.      operands in OPERANDS to be suitable for the low-numbered word.  */
  416.  
  417.   if (optype0 == REGOP)
  418.     latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
  419.   else if (optype0 == OFFSOP)
  420.     latehalf[0] = adj_offsettable_operand (operands[0], 4);
  421.   else
  422.     latehalf[0] = operands[0];
  423.  
  424.   if (optype1 == REGOP)
  425.     latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
  426.   else if (optype1 == OFFSOP)
  427.     latehalf[1] = adj_offsettable_operand (operands[1], 4);
  428.   else if (optype1 == CNSTOP)
  429.     {
  430.       if (CONSTANT_P (operands[1]))
  431.     latehalf[1] = const0_rtx;
  432.       else if (GET_CODE (operands[1]) == CONST_DOUBLE)
  433.     {
  434.       union { REAL_VALUE_TYPE e; int i[3]; } ue;
  435.       union { double d; int i[2]; } ud;
  436.  
  437.       ue.i[0] = CONST_DOUBLE_LOW (operands[1]);
  438.       ue.i[1] = CONST_DOUBLE_HIGH (operands[1]);
  439.       ue.i[2] = CONST_DOUBLE_TOP (operands[1]);
  440.  
  441.       ud.d = ue.e;
  442.  
  443.       latehalf[1] = gen_rtx (CONST_INT, VOIDmode, ud.i[1]);
  444.       operands[1] = gen_rtx (CONST_INT, VOIDmode, ud.i[0]);
  445.     }
  446.     }
  447.   else
  448.     latehalf[1] = operands[1];
  449.  
  450.   /* If insn is effectively movd N(sp),-(sp) then we will do the
  451.      high word first.  We should use the adjusted operand 1 (which is N+4(sp))
  452.      for the low word as well, to compensate for the first decrement of sp.  */
  453.   if (optype0 == PUSHOP
  454.       && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
  455.       && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
  456.     operands[1] = latehalf[1];
  457.  
  458.   /* If one or both operands autodecrementing,
  459.      do the two words, high-numbered first.  */
  460.  
  461.   /* Likewise,  the first move would clobber the source of the second one,
  462.      do them in the other order.  This happens only for registers;
  463.      such overlap can't happen in memory unless the user explicitly
  464.      sets it up, and that is an undefined circumstance.  */
  465.  
  466.   if (optype0 == PUSHOP || optype1 == PUSHOP
  467.       || (optype0 == REGOP && optype1 == REGOP
  468.       && REGNO (operands[0]) == REGNO (latehalf[1])))
  469.     {
  470.       /* Make any unoffsettable addresses point at high-numbered word.  */
  471.       if (addreg0)
  472.     output_asm_insn ("addql #4,%0", &addreg0);
  473.       if (addreg1)
  474.     output_asm_insn ("addql #4,%0", &addreg1);
  475.  
  476.       /* Do that word.  */
  477.       output_asm_insn (singlemove_string (latehalf), latehalf);
  478.  
  479.       /* Undo the adds we just did.  */
  480.       if (addreg0)
  481.     output_asm_insn ("subql #4,%0", &addreg0);
  482.       if (addreg1)
  483.     output_asm_insn ("subql #4,%0", &addreg1);
  484.  
  485.       /* Do low-numbered word.  */
  486.       output_asm_insn (singlemove_string (operands), operands);
  487.  
  488.       return "";
  489.     }
  490.  
  491.   /* Normal case: do the two words, low-numbered first.  */
  492.  
  493.   output_asm_insn (singlemove_string (operands), operands);
  494.  
  495.   /* Make any unoffsettable addresses point at high-numbered word.  */
  496.   if (addreg0)
  497.     output_asm_insn ("addql #4,%0", &addreg0);
  498.   if (addreg1)
  499.     output_asm_insn ("addql #4,%0", &addreg1);
  500.  
  501.   /* Do that word.  */
  502.   output_asm_insn (singlemove_string (latehalf), latehalf);
  503.  
  504.   /* Undo the adds we just did.  */
  505.   if (addreg0)
  506.     output_asm_insn ("subql #4,%0", &addreg0);
  507.   if (addreg1)
  508.     output_asm_insn ("subql #4,%0", &addreg1);
  509.  
  510.   return "";
  511. }
  512.  
  513. /* Output assembler code to perform a long double move insn
  514.    with operands OPERANDS.  */
  515.  
  516. char *
  517. output_move_extended (operands)
  518.      rtx *operands;
  519. {
  520.   enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
  521.   rtx latehalf[2], thirdhalf[2];
  522.   rtx addreg0 = 0, addreg1 = 0;
  523.  
  524.   /* First classify both operands.  */
  525.  
  526.   if (REG_P (operands[0]))
  527.     optype0 = REGOP;
  528.   else if (offsettable_memref_p (operands[0]))
  529.     optype0 = OFFSOP;
  530.   else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
  531.     optype0 = POPOP;
  532.   else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
  533.     optype0 = PUSHOP;
  534.   else if (GET_CODE (operands[0]) == MEM)
  535.     optype0 = MEMOP;
  536.   else
  537.     optype0 = RNDOP;
  538.  
  539.   if (REG_P (operands[1]))
  540.     optype1 = REGOP;
  541.   else if (CONSTANT_P (operands[1])
  542.        || GET_CODE (operands[1]) == CONST_DOUBLE)
  543.     optype1 = CNSTOP;
  544.   else if (offsettable_memref_p (operands[1]))
  545.     optype1 = OFFSOP;
  546.   else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
  547.     optype1 = POPOP;
  548.   else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
  549.     optype1 = PUSHOP;
  550.   else if (GET_CODE (operands[1]) == MEM)
  551.     optype1 = MEMOP;
  552.   else
  553.     optype1 = RNDOP;
  554.  
  555.   /* Check for the cases that the operand constraints are not
  556.      supposed to allow to happen.  Abort if we get one,
  557.      because generating code for these cases is painful.  */
  558.  
  559.   if (optype0 == RNDOP || optype1 == RNDOP || optype0 == MEMOP || optype1 == MEMOP)
  560.     abort ();
  561.  
  562.   /* If one operand is decrementing and one is incrementing
  563.      decrement the former register explicitly
  564.      and change that operand into ordinary indexing.  */
  565.  
  566.   if (optype0 == PUSHOP && optype1 == POPOP)
  567.     {
  568.       operands[0] = XEXP (XEXP (operands[0], 0), 0);
  569.       output_asm_insn ("subq.l #12345,%0", operands);
  570.       operands[0] = gen_rtx (MEM, DImode, operands[0]);
  571.       optype0 = OFFSOP;
  572.     }
  573.   if (optype0 == POPOP && optype1 == PUSHOP)
  574.     {
  575.       operands[1] = XEXP (XEXP (operands[1], 0), 0);
  576.       output_asm_insn ("subq.l #12345,%1", operands);
  577.       operands[1] = gen_rtx (MEM, DImode, operands[1]);
  578.       optype1 = OFFSOP;
  579.     }
  580.  
  581.   /* Ok, we can do one word at a time.
  582.      Normally we do the low-numbered word first,
  583.      but if either operand is autodecrementing then we
  584.      do the high-numbered word first.
  585.  
  586.      In either case, set up in LATEHALF the operands to use
  587.      for the high-numbered word and in some cases alter the
  588.      operands in OPERANDS to be suitable for the low-numbered word.  */
  589.  
  590.   if (optype0 == REGOP)
  591.     latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
  592.   else if (optype0 == OFFSOP)
  593.     latehalf[0] = adj_offsettable_operand (operands[0], (TARGET_68881 ? 4 :2));
  594.   else
  595.     latehalf[0] = operands[0];
  596.  
  597.   if (optype1 == REGOP)
  598.     latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
  599.   else if (optype1 == OFFSOP)
  600.     latehalf[1] = adj_offsettable_operand (operands[1], (TARGET_68881 ? 4 :2));
  601.   else if (optype1 == CNSTOP)
  602.     {
  603.       if (CONSTANT_P (operands[1]))
  604.     latehalf[1] = const0_rtx;
  605.       else if (GET_CODE (operands[1]) == CONST_DOUBLE)
  606.     {
  607.       latehalf[1] = gen_rtx (CONST_INT, VOIDmode,
  608.                  CONST_DOUBLE_HIGH (operands[1]));
  609.     }
  610.     }
  611.   else
  612.     latehalf[1] = operands[1];
  613.  
  614.   if (optype0 == REGOP)
  615.     thirdhalf[0] = gen_rtx (REG, SImode,
  616.                 ((!TARGET_68881 && REGNO (operands[0]) == 0) ?
  617.                  8 :
  618.                  REGNO (operands[0]) + 2));
  619.   else if (optype0 == OFFSOP)
  620.     thirdhalf[0] = adj_offsettable_operand (operands[0], (TARGET_68881 ? 8:6));
  621.   else
  622.     thirdhalf[0] = operands[0];
  623.  
  624.   if (optype1 == REGOP)
  625.     thirdhalf[1] = gen_rtx (REG, SImode,
  626.                 ((!TARGET_68881 && REGNO (operands[1]) == 0) ?
  627.                  8 :
  628.                  REGNO (operands[1]) + 2));
  629.   else if (optype1 == OFFSOP)
  630.     thirdhalf[1] = adj_offsettable_operand (operands[1], (TARGET_68881 ? 8:6));
  631.   else if (optype1 == CNSTOP)
  632.     {
  633.       if (CONSTANT_P (operands[1]))
  634.     thirdhalf[1] = const0_rtx;
  635.       else if (GET_CODE (operands[1]) == CONST_DOUBLE)
  636.     {
  637.       thirdhalf[1] = gen_rtx (CONST_INT, VOIDmode,
  638.                  CONST_DOUBLE_TOP (operands[1]));
  639.       operands[1] = gen_rtx (CONST_INT, VOIDmode,
  640.                  (TARGET_68881 ? CONST_DOUBLE_LOW (operands[1])
  641.                                                  : ((unsigned int) CONST_DOUBLE_LOW (operands[1])) >> 16));
  642.     }
  643.     }
  644.   else
  645.     thirdhalf[1] = operands[1];
  646.  
  647.   /* If insn is effectively movd N(sp),-(sp) then we will do the
  648.      high word first.  We should use the adjusted operand 1 (which is N+4(sp))
  649.      for the low word as well, to compensate for the first decrement of sp.  */
  650.   if (optype0 == PUSHOP
  651.       && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
  652.       && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
  653.     operands[1] = latehalf[1];
  654.  
  655.   /* If one or both operands autodecrementing,
  656.      do the two words, high-numbered first.  */
  657.  
  658.     
  659.   /* Likewise,  the first move would clobber the source of the second one,
  660.      do them in the other order.  This happens only for registers;
  661.      such overlap can't happen in memory unless the user explicitly
  662.      sets it up, and that is an undefined circumstance.  */
  663.  
  664.   if (optype0 == PUSHOP || optype1 == PUSHOP
  665.       || (optype0 == REGOP && optype1 == REGOP
  666.       && REGNO (operands[0]) == REGNO (latehalf[1])))
  667.     {
  668.       output_asm_insn (singlemove_string (thirdhalf), thirdhalf);
  669.  
  670.       output_asm_insn (singlemove_string (latehalf), latehalf);
  671.  
  672.       if (TARGET_68881)
  673.     output_asm_insn (singlemove_string (operands), operands);
  674.       else
  675.     output_asm_insn ("move.w %1,%0", operands);
  676.  
  677.       return "";
  678.     }
  679.  
  680.   /* Normal case: do the three words, low-numbered first.  */
  681.  
  682.   if (TARGET_68881)
  683.     output_asm_insn (singlemove_string (operands), operands);
  684.   else
  685.     output_asm_insn ("move.w %1,%0", operands);
  686.  
  687.   output_asm_insn (singlemove_string (latehalf), latehalf);
  688.  
  689.   output_asm_insn (singlemove_string (thirdhalf), thirdhalf);
  690.  
  691.   return "";
  692. }
  693.  
  694. /* Generate code for one of the extended-to-integer lib calls.  The context
  695.    is such that we can't make call rtxes, and have to do it all manually. */
  696.  
  697. char *
  698. output_lib_convert (operands, name)
  699.      rtx *operands;
  700.      char *name;
  701. {
  702.   rtx aoperands[2];
  703.   char tmpbuf[1000];
  704.   int pushed = 0;
  705.  
  706.   /* What regs need to be saved/restored? probably several... */
  707.   /* Set up a new operand array. */
  708.   aoperands[0] = gen_rtx (MEM, GET_MODE (aoperands[1]),
  709.               gen_rtx (PRE_DEC, Pmode, stack_pointer_rtx));
  710.   aoperands[1] = operands[1];
  711.   /* We need a pointer to the float; try different ways to get one. */
  712.   if (GET_CODE (aoperands[1]) == MEM)
  713.     {
  714.       output_asm_insn ("pea %1", aoperands);
  715.     }
  716.   else if (FP_REG_P (aoperands[1]))
  717.     {
  718.       output_asm_insn ("fmove.x %1,%0", aoperands);
  719.       output_asm_insn ("pea 0(sp)", NULL);
  720.       pushed = 1;
  721.     }
  722.   else
  723.     {
  724.       output_move_extended (aoperands);
  725.       output_asm_insn ("pea 0(sp)", NULL);
  726.       pushed = 1;
  727.     }
  728.   /* Do an on-the-spot importation of the libcall name. */
  729.   sprintf (tmpbuf, "IMPORT %s", name);
  730.   output_asm_insn (tmpbuf, NULL);
  731.   /* Now go and do it. */
  732.   if (TARGET_FX30)
  733.     sprintf (tmpbuf, "DC.W $61ff ; bsr.l\;DC.L %s-m#start-*", name);
  734.   else
  735.     sprintf (tmpbuf, "jsr %s", name);
  736.   output_asm_insn (tmpbuf, NULL);
  737.   /* If intended result place is not d0, move it there. */
  738.   if (! (REG_P (operands[0]) && REGNO (operands[0]) == 0))
  739.     {
  740.       aoperands[0] = operands[0];
  741.       aoperands[1] = gen_rtx (REG, SImode, 0);
  742.       output_asm_insn (singlemove_string (aoperands), aoperands);
  743.     }
  744.   /* Fix up the stack (we pushed a pointer and maybe an extended float
  745.      for it to point to). */
  746.   sprintf (tmpbuf, "add.w #%d,sp",
  747.        4 + (pushed ? mode_size[(int) XFmode] : 0));
  748.   output_asm_insn(tmpbuf, NULL);
  749.   return "";
  750. }
  751.  
  752. /* The int library call convention is to use D0 and D1 with output to D0.
  753.    The complication here is that regalloc is already complete, so we have
  754.    to be very careful not to step on any important values.  From md we
  755.    *are* guaranteed that output is a Dn, while input is either Dn or a
  756.    constant, which simplifies things considerably. */
  757.  
  758. /*   (I'm not 100% convinced that this code is correct...) */
  759.  
  760. char *
  761. output_int_lib_call (operands, name)
  762.      rtx *operands;
  763.      char *name;
  764. {
  765.   char tmpbuf[1000];
  766.   int o0d0 = 0, o2d0 = 0, o0d1 = 0, o2d1 = 0, o0d2 = 0;
  767.  
  768.   /* Int lib routines may step on a0. */
  769.   output_asm_insn ("movem.l a0/a1,-(sp)", NULL);
  770.  
  771.   if (GET_CODE (operands[0]) == REG && REGNO (operands[0]) == 0) o0d0 = 1;
  772.   if (GET_CODE (operands[0]) == REG && REGNO (operands[0]) == 1) o0d1 = 1;
  773.   if (GET_CODE (operands[0]) == REG && REGNO (operands[0]) == 2) o0d2 = 1;
  774.   if (GET_CODE (operands[2]) == REG && REGNO (operands[2]) == 0) o2d0 = 1;
  775.   if (GET_CODE (operands[2]) == REG && REGNO (operands[2]) == 1) o2d1 = 1;
  776.  
  777.     if (!o0d1)
  778.         output_asm_insn ("move.l d1,-(sp)", NULL);
  779.  
  780.     if (!o0d2)
  781.         output_asm_insn ("move.l d2,-(sp)", NULL);
  782.  
  783.     if (o0d0)
  784.     {
  785.         if (o2d1)
  786.         {
  787.             /* everything is exactly where we want it */
  788.         } 
  789.         else
  790.         {
  791.             /* move operand 2 into d1. */
  792.             output_asm_insn ("move.l %2,d1", operands);
  793.         }
  794.     }
  795.     else
  796.     {
  797.         /* operand 0 is not in d0, so we need to save d0 on the stack before
  798.            copying the operand to d0. */
  799.         output_asm_insn ("move.l d0,-(sp)", NULL);
  800.         if (o0d1) 
  801.         {
  802.             output_asm_insn ("move.l d1,d0", NULL);
  803.             if (o2d0) 
  804.             {
  805.                 /* Input and output are in exactly the opposite of where we want. */
  806.                 /* d0 just got saved on the stack, so we can copy it from the stack
  807.                    to d1.  Note that we are copying the value not popping it off, so
  808.                    that we can restore d0 later. */
  809.                 output_asm_insn ("move.l (sp),d1", NULL);
  810.             } 
  811.             else 
  812.             {
  813.                 /* move the input to d1. */
  814.                 output_asm_insn ("move.l %2,d1", operands);
  815.             }
  816.         } 
  817.         else 
  818.         {
  819.             if (!o2d1)
  820.             {
  821.                 /* operand 2 is not in d1, so we gotta move it to d1 */
  822.                 output_asm_insn ("move.l %2,d1", operands);
  823.             }
  824.             /* operand 0 is not in either d0 or d1, so we gotta move it to d0 */
  825.             output_asm_insn ("move.l %0,d0", operands);
  826.         }
  827.     }
  828.  
  829.   /* Do the int lib call proper now. */
  830.   sprintf (tmpbuf, "IMPORT %s", name);
  831.   output_asm_insn (tmpbuf, NULL);
  832.   if (TARGET_FX30)
  833.     sprintf (tmpbuf, "DC.W $61ff ; bsr.l\;DC.L %s-m#start-*", name);
  834.   else
  835.     sprintf (tmpbuf, "jsr %s", name);
  836.   output_asm_insn (tmpbuf, NULL);
  837.  
  838.   /* Now clean up any mess we might have made on the stack, plus move the
  839.      result from d0 to wherever it was supposed to go. */
  840.  
  841.   /* If operand 0 was not in d0, move the output to the correct place and then
  842.        restore d0 */
  843.   if (!o0d0)
  844.     {
  845.     output_asm_insn ("move.l d0,%0", operands);
  846.     output_asm_insn ("move.l (sp)+,d0", NULL);
  847.     }
  848.  
  849.   if (!o0d2)
  850.     output_asm_insn ("move.l (sp)+,d2", NULL);
  851.  
  852.   if (!o0d1)
  853.     output_asm_insn ("move.l (sp)+,d1", NULL);
  854.     
  855.   /* restore a0, a1, d1, and d2 */
  856.   output_asm_insn ("movem.l (sp)+,a0/a1", NULL);
  857.  
  858.   return "";
  859. }
  860.  
  861. /* Helper stuff for SANE output routines. */
  862.  
  863. #define STKOFF(MODE,OFF)  \
  864.   gen_rtx (MEM, (MODE), gen_rtx (PLUS, Pmode, stack_pointer_rtx,  \
  865.                    gen_rtx (CONST_INT, VOIDmode, (OFF))))
  866.  
  867. /* This takes a stack reference and changes it into a stack reference
  868.    4 bytes deeper.  This is needed after a push on the stack. */
  869.  
  870. rtx deepen (x)
  871.      rtx x;
  872. {
  873.   if (GET_CODE (x) == MEM
  874.       && GET_CODE (XEXP (x, 0)) == PLUS
  875.       && XEXP (XEXP (x, 0), 0) == stack_pointer_rtx)
  876.     {
  877.       return STKOFF (GET_MODE (x), 4 + INTVAL (XEXP (XEXP (x, 0), 1)));
  878.     }
  879.   else
  880.     return x;
  881. }
  882.  
  883. /* Output a 2(1)-address operation that uses SANE. */
  884.  
  885. char *
  886. output_sane_2 (opnds, op, name)
  887.      rtx *opnds;
  888.      int op;
  889.      char *name;
  890. {
  891.   char tmpbuf[100], *cname;
  892.   enum machine_mode mode0 = GET_MODE (opnds[0]);
  893.   int space0 = 0, spacetmp = 0, space;
  894.   int cop;
  895.   rtx operands[2], moperands[2], coperands[2], tmprtx;
  896.  
  897.   if (mode0 != XFmode)
  898.     spacetmp = GET_MODE_SIZE (XFmode);
  899.   if (REG_P (opnds[0]) || GET_CODE (opnds[0]) == CONST_DOUBLE)
  900.     space0 = GET_MODE_SIZE (GET_MODE (opnds[0]));
  901.   space = spacetmp + space0;
  902.   /* Reserve needed space for all our tmps and operands. */
  903.   if (spacetmp > 0)
  904.     {
  905.       sprintf(tmpbuf, "sub.w #%d,sp", spacetmp);
  906.       output_asm_insn(tmpbuf, NULL);
  907.       tmprtx = STKOFF (XFmode, space0);
  908.     }
  909.   if (space0 > 0)
  910.     {
  911.       output_sane_push(opnds[0]);
  912.       operands[0] = STKOFF (GET_MODE (opnds[0]), 0);
  913.     }
  914.   else
  915.     {
  916.       operands[0] = opnds[0];
  917.     }
  918.   /* Now everything is a pointer to memlocs where the numbers reside. */
  919.   /* First order of business is to make sure the input-output operand
  920.      is of extended type.  If not, then we convert into a reserved place
  921.      and if so, we maybe put it on the stack anyway. */
  922.   if (mode0 != XFmode)
  923.     {
  924.       cop = (mode0 == HImode ? 0x200e :
  925.          (mode0 == SImode ? 0x280e :
  926.           (mode0 == SFmode ? 0x100e :
  927.            0x080e)));
  928.       cname = (mode0 == HImode ? "FI2X" :
  929.            (mode0 == SImode ? "FL2X" :
  930.         (mode0 == SFmode ? "FS2X" :
  931.          "FD2X")));
  932.       coperands[1] = operands[0];
  933.       coperands[0] = deepen (tmprtx);
  934.       output_sane_op (coperands, 2, cop, cname);
  935.       moperands[0] = tmprtx;
  936.     }
  937.   else
  938.     {
  939.       moperands[0] = operands[0];
  940.     }
  941.   /* Now we're all set to do the operation proper. */
  942.   output_sane_op (moperands, 1, op, name);
  943.   /* The result of the operation is still extended, so we may need to
  944.      do another conversion.  Fortunately, the extended result is already in
  945.      memory, so we don't need to allocate, but the final result may need
  946.      to be sent back to regs. */
  947.   if (mode0 != XFmode)
  948.     {
  949.       cop = (mode0 == HImode ? 0x2010 :
  950.          (mode0 == SImode ? 0x2810 :
  951.           (mode0 == SFmode ? 0x1010 :
  952.            0x0810)));
  953.       cname = (mode0 == HImode ? "FX2I" :
  954.            (mode0 == SImode ? "FX2L" :
  955.         (mode0 == SFmode ? "FX2S" :
  956.          "FX2D")));
  957.       coperands[0] = deepen (operands[0]);
  958.       coperands[1] = moperands[0];
  959.       output_sane_op (coperands, 2, cop, cname);
  960.     }
  961.   /* SANE calls all done, now clean up. */
  962.   /* Pop the result if it had to be pushed originally. */
  963.   if (REG_P (opnds[0]) || GET_CODE (opnds[0]) == CONST_DOUBLE)
  964.     {
  965.       output_sane_pop (opnds[0]);
  966.     }
  967.   /* Deallocate everything else. */
  968.   if (spacetmp > 0)
  969.     {
  970.       sprintf (tmpbuf, "add.w #%d,sp", spacetmp);
  971.       output_asm_insn(tmpbuf, NULL);
  972.     }
  973.   /* All the code has already been dumped out. */
  974.   return "";
  975. }
  976.  
  977. /* Output a compare operation that uses SANE (two float operands, integer
  978.    result). */
  979.  
  980. char *
  981. output_sane_cmp (opnds, op, name)
  982.      rtx *opnds;
  983.      int op;
  984.      char *name;
  985. {
  986.   char tmpbuf[100], *cname;
  987.   enum machine_mode mode0 = GET_MODE (opnds[0]);
  988.   enum machine_mode mode1 = GET_MODE (opnds[1]);
  989.   int space0 = 0, space1 = 0, spacetmp = 0, space;
  990.   int cop;
  991.   rtx operands[3], moperands[3], coperands[2], tmprtx, tmpop;
  992.  
  993.   if (mode0 != XFmode)
  994.     spacetmp = GET_MODE_SIZE (XFmode);
  995.   if (REG_P (opnds[0])  || GET_CODE (opnds[0]) == CONST_DOUBLE)
  996.     space0 = GET_MODE_SIZE (GET_MODE (opnds[0]));
  997.   if (REG_P (opnds[1]) || GET_CODE (opnds[1]) == CONST_DOUBLE)
  998.     space1 = GET_MODE_SIZE (GET_MODE (opnds[1]));
  999.   space = spacetmp + space1 + space0;
  1000.   /* Reserve needed space for all our tmps and operands. */
  1001.   if (spacetmp > 0)
  1002.     {
  1003.       sprintf(tmpbuf, "sub.w #%d,sp", spacetmp);
  1004.       output_asm_insn(tmpbuf, NULL);
  1005.       tmprtx = STKOFF (XFmode, space0 + space1);
  1006.     }
  1007.   if (space1 > 0)
  1008.     {
  1009.       output_sane_push(opnds[1]);
  1010.       operands[1] = STKOFF (GET_MODE (opnds[1]), space0);
  1011.     }
  1012.   else
  1013.     {
  1014.       operands[1] = opnds[1];
  1015.     }
  1016.   if (space0 > 0)
  1017.     {
  1018.       output_sane_push(opnds[0]);
  1019.       operands[0] = STKOFF (GET_MODE (opnds[0]), 0);
  1020.     }
  1021.   else
  1022.     {
  1023.       operands[0] = opnds[0];
  1024.     }
  1025.   /* Now everything is a pointer to memlocs where the numbers reside. */
  1026.   /* First order of business is to make sure the first operand
  1027.      is of extended type.  If not, then we convert into a reserved place
  1028.      and if so, we maybe put it on the stack anyway. */
  1029.   if (mode0 != XFmode)
  1030.     {
  1031.       cop = (mode0 == HImode ? 0x200e :
  1032.          (mode0 == SImode ? 0x280e :
  1033.           (mode0 == SFmode ? 0x100e :
  1034.            0x080e)));
  1035.       cname = (mode0 == HImode ? "FI2X" :
  1036.            (mode0 == SImode ? "FL2X" :
  1037.         (mode0 == SFmode ? "FS2X" :
  1038.          "FD2X")));
  1039.       coperands[1] = operands[0];
  1040.       coperands[0] = deepen (tmprtx);
  1041.       output_sane_op (coperands, 2, cop, cname);
  1042.       moperands[0] = tmprtx;
  1043.     }
  1044.   else
  1045.     {
  1046.       moperands[0] = operands[0];
  1047.     }
  1048.   tmpop = moperands[0];
  1049.   moperands[0] = deepen (moperands[0]);
  1050.   moperands[1] = operands[1];
  1051.   /* Now we're all set to do the comparison proper. */
  1052.   output_sane_op (moperands, 2, op, name);
  1053.   /* Deallocate everything else.  Note that this add is really adda,
  1054.      so condition codes coming back from SANE op are still valid. */
  1055.   if (spacetmp + space1 + space0 > 0)
  1056.     {
  1057.       sprintf (tmpbuf, "add.w #%d,sp", spacetmp + space1 + space0);
  1058.       output_asm_insn(tmpbuf, NULL);
  1059.     }
  1060.   /* All the code has already been dumped out. */
  1061.   return "";
  1062. }
  1063.  
  1064. /* Output a compare against 0 by synthesizing the zero and calling cmp. */
  1065.  
  1066. char *
  1067. output_sane_tst (opnds, op, name)
  1068.      rtx *opnds;
  1069.      int op;
  1070.      char *name;
  1071. {
  1072.   enum machine_mode mode0 = GET_MODE (opnds[0]);
  1073.   rtx operands[2];
  1074.  
  1075.   operands[0] = opnds[0];
  1076.   operands[1] = CONST0_RTX (mode0);
  1077.   return output_sane_cmp (operands, op, name);
  1078. }
  1079.  
  1080. /* Output a conversion operation that uses SANE.  This is sort of like
  1081.    a two-address operation, except that conversions aren't needed... */
  1082.  
  1083. char *
  1084. output_sane_convert (opnds)
  1085.      rtx *opnds;
  1086. {
  1087.   char tmpbuf[100], *cname;
  1088.   enum machine_mode frommode = GET_MODE (opnds[1]);
  1089.   enum machine_mode tomode   = GET_MODE (opnds[0]);
  1090.   int space0 = 0, space1 = 0, spacetmp = 0, space;
  1091.   int cop;
  1092.   rtx operands[3], moperands[3], coperands[2], tmprtx, tmpop;
  1093.  
  1094.   if (frommode == tomode) abort();  /* should never happen? */
  1095.  
  1096.   if (frommode != XFmode && tomode != XFmode)
  1097.     spacetmp = GET_MODE_SIZE (XFmode);
  1098.   if (REG_P (opnds[0]) || GET_CODE (opnds[0]) == CONST_DOUBLE)
  1099.     space0 = GET_MODE_SIZE (GET_MODE (opnds[0]));
  1100.   if (REG_P (opnds[1]) || GET_CODE (opnds[1]) == CONST_DOUBLE)
  1101.     space1 = GET_MODE_SIZE (GET_MODE (opnds[1]));
  1102.   space = spacetmp + space1 + space0;
  1103.   /* Reserve needed space for all our tmps and operands. */
  1104.   if (spacetmp > 0)
  1105.     {
  1106.       sprintf(tmpbuf, "sub.w #%d,sp", spacetmp);
  1107.       output_asm_insn(tmpbuf, NULL);
  1108.       tmprtx = STKOFF (XFmode, space0 + space1);
  1109.     }
  1110.   if (space1 > 0)
  1111.     {
  1112.       output_sane_push(opnds[1]);
  1113.       operands[1] = STKOFF (GET_MODE (opnds[1]), space0);
  1114.     }
  1115.   else
  1116.     {
  1117.       operands[1] = opnds[1];
  1118.     }
  1119.   if (space0 > 0)
  1120.     {
  1121.       output_sane_push(opnds[0]);
  1122.       operands[0] = STKOFF (GET_MODE (opnds[0]), 0);
  1123.     }
  1124.   else
  1125.     {
  1126.       operands[0] = opnds[0];
  1127.     }
  1128.   if (frommode != XFmode)
  1129.     {
  1130.       cop = (frommode == HImode ? 0x200e :
  1131.          (frommode == SImode ? 0x280e :
  1132.           (frommode == SFmode ? 0x100e :
  1133.            0x080e)));
  1134.       cname = (frommode == HImode ? "FI2X" :
  1135.            (frommode == SImode ? "FL2X" :
  1136.         (frommode == SFmode ? "FS2X" :
  1137.          "FD2X")));
  1138.       coperands[1] = operands[1];
  1139.       coperands[0] = deepen (tomode == XFmode ? operands[0] : tmprtx);
  1140.       output_sane_op (coperands, 2, cop, cname);
  1141.     }
  1142.   /* If necessary, do the second conversion. */
  1143.   if (tomode != XFmode)
  1144.     {
  1145.       cop = (tomode == HImode ? 0x2010 :
  1146.          (tomode == SImode ? 0x2810 :
  1147.           (tomode == SFmode ? 0x1010 :
  1148.            0x0810)));
  1149.       cname = (tomode == HImode ? "FX2I" :
  1150.            (tomode == SImode ? "FX2L" :
  1151.         (tomode == SFmode ? "FX2S" :
  1152.          "FX2D")));
  1153.       coperands[1] = (frommode == XFmode ? operands[1] : tmprtx);
  1154.       coperands[0] = deepen (operands[0]);
  1155.       output_sane_op (coperands, 2, cop, cname);
  1156.     }
  1157.   /* Pop the result if it wasn't memory-resident */
  1158.   if (REG_P (opnds[0]) || GET_CODE (opnds[0]) == CONST_DOUBLE)
  1159.     {
  1160.       output_sane_pop (opnds[0]);
  1161.     }
  1162.   /* Finish cleaning up the stack. */
  1163.   if (spacetmp + space1 > 0)
  1164.     {
  1165.       sprintf (tmpbuf, "add.w #%d,sp", spacetmp + space1);
  1166.       output_asm_insn(tmpbuf, NULL);
  1167.     }
  1168.   return "";
  1169. }
  1170.  
  1171. /* Output a 3(2)-address operation that uses SANE.  This routine will do
  1172.    everything including type conversions, since this helps it use the
  1173.    stack somewhat more efficiently. */
  1174.  
  1175. char *
  1176. output_sane_3 (opnds, op, name)
  1177.      rtx *opnds;
  1178.      int op;
  1179.      char *name;
  1180. {
  1181.     char tmpbuf[100], *cname;
  1182.     enum machine_mode mode0 = GET_MODE (opnds[0]);
  1183.     enum machine_mode mode2 = GET_MODE (opnds[2]);
  1184.     int space0 = 0, space2 = 0, spacetmp = 0, space;
  1185.     int cop;
  1186.     rtx operands[3], moperands[3], coperands[2], tmprtx, tmpop;
  1187.  
  1188.     if (mode0 != XFmode)
  1189.       spacetmp = GET_MODE_SIZE (XFmode);
  1190.     if (REG_P (opnds[0]) || GET_CODE (opnds[0]) == CONST_DOUBLE)
  1191.       space0 = GET_MODE_SIZE (GET_MODE (opnds[0]));
  1192.     if (REG_P (opnds[2]) || GET_CODE (opnds[2]) == CONST_DOUBLE)
  1193.       space2 = GET_MODE_SIZE (GET_MODE (opnds[2]));
  1194.     space = spacetmp + space2 + space0;
  1195.     /* Reserve needed space for all our tmps and operands. */
  1196.     if (spacetmp > 0)
  1197.       {
  1198.     sprintf(tmpbuf, "sub.w #%d,sp", spacetmp);
  1199.     output_asm_insn(tmpbuf, NULL);
  1200.     tmprtx = STKOFF (XFmode, space0 + space2);
  1201.       }
  1202.     if (space2 > 0)
  1203.       {
  1204.     output_sane_push(opnds[2]);
  1205.     operands[2] = STKOFF (GET_MODE (opnds[2]), space0);
  1206.       }
  1207.     else
  1208.       {
  1209.     operands[2] = opnds[2];
  1210.       }
  1211.     if (space0 > 0)
  1212.       {
  1213.     output_sane_push(opnds[0]);
  1214.     operands[0] = STKOFF (GET_MODE (opnds[0]), 0);
  1215.       }
  1216.     else
  1217.       {
  1218.     operands[0] = opnds[0];
  1219.       }
  1220.     /* Now everything is a pointer to memlocs where the numbers reside. */
  1221.     /* First order of business is to make sure the input-output operand
  1222.        is of extended type.  If not, then we convert into a reserved place
  1223.        and if so, we maybe put it on the stack anyway. */
  1224.     if (mode0 != XFmode)
  1225.       {
  1226.       cop = (mode0 == HImode ? 0x200e :
  1227.          (mode0 == SImode ? 0x280e :
  1228.           (mode0 == SFmode ? 0x100e :
  1229.            0x080e)));
  1230.       cname = (mode0 == HImode ? "FI2X" :
  1231.            (mode0 == SImode ? "FL2X" :
  1232.             (mode0 == SFmode ? "FS2X" :
  1233.              "FD2X")));
  1234.     coperands[1] = operands[0];
  1235.     coperands[0] = deepen (tmprtx);
  1236.     output_sane_op (coperands, 2, cop, cname);
  1237.     moperands[0] = tmprtx;
  1238.       }
  1239.     else
  1240.       {
  1241.     moperands[0] = operands[0];
  1242.       }
  1243.     tmpop = moperands[0];
  1244.     moperands[0] = deepen (moperands[0]);
  1245.     moperands[1] = operands[2];
  1246.     /* Now we're all set to do the operation proper. */
  1247.     output_sane_op (moperands, 2, op, name);
  1248.     /* The result of the operation is still extended, so we may need to
  1249.        do another conversion.  Fortunately, the extended result is already in
  1250.        memory, so we don't need to allocate, but the final result may need
  1251.        to be sent back to regs. */
  1252.     if (mode0 != XFmode)
  1253.       {
  1254.       cop = (mode0 == HImode ? 0x2010 :
  1255.          (mode0 == SImode ? 0x2810 :
  1256.           (mode0 == SFmode ? 0x1010 :
  1257.            0x0810)));
  1258.       cname = (mode0 == HImode ? "FX2I" :
  1259.            (mode0 == SImode ? "FX2L" :
  1260.             (mode0 == SFmode ? "FX2S" :
  1261.              "FX2D")));
  1262.       coperands[0] = deepen (operands[0]);
  1263.       coperands[1] = tmpop;
  1264.       output_sane_op (coperands, 2, cop, cname);
  1265.       }
  1266.     /* SANE calls all done, now clean up. */
  1267.     /* Pop the result if it had to be pushed originally. */
  1268.     if (REG_P (opnds[0]) || GET_CODE (opnds[0]) == CONST_DOUBLE)
  1269.       {
  1270.     output_sane_pop (opnds[0]);
  1271.       }
  1272.     /* Deallocate everything else. */
  1273.     if (spacetmp + space2 > 0)
  1274.       {
  1275.     sprintf (tmpbuf, "add.w #%d,sp", spacetmp + space2);
  1276.     output_asm_insn(tmpbuf, NULL);
  1277.       }
  1278.     /* All the code has already been dumped out. */
  1279.     return "";
  1280. }
  1281.  
  1282. /* Push a SANE number onto the stack (usually from a reg). */
  1283.  
  1284. output_sane_push (x)
  1285.      rtx x;
  1286. {
  1287.   rtx pusherands[2];
  1288.  
  1289.   pusherands[0] = gen_rtx (MEM, GET_MODE (x),
  1290.                  gen_rtx (PRE_DEC, Pmode, stack_pointer_rtx));
  1291.   pusherands[1] = x;
  1292.   switch (GET_MODE (x))
  1293.     {
  1294.     case HImode:
  1295.       output_asm_insn ("move.w %1,%0", pusherands);
  1296.       break;
  1297.     case SImode:
  1298.     case SFmode:
  1299.       output_asm_insn ("move.l %f1,%0", pusherands);
  1300.       break;
  1301.     case DFmode:
  1302.       output_move_double (pusherands);
  1303.       break;
  1304.     case XFmode:
  1305.       output_move_extended (pusherands);
  1306.       break;
  1307.     default:
  1308.       abort();
  1309.     }
  1310. }
  1311.  
  1312. /* Pop a SANE number off the stack into a given place (most likely a reg). */
  1313.  
  1314. output_sane_pop (x)
  1315.      rtx x;
  1316. {
  1317.   rtx poperands[2];
  1318.  
  1319.   poperands[0] = x;
  1320.   poperands[1] = gen_rtx (MEM, GET_MODE (x),
  1321.               gen_rtx (POST_INC, Pmode, stack_pointer_rtx));
  1322.   switch (GET_MODE (x))
  1323.     {
  1324.     case HImode:
  1325.       output_asm_insn ("move.w %1,%0", poperands);
  1326.       break;
  1327.     case SImode:
  1328.     case SFmode:
  1329.       output_asm_insn ("move.l %1,%0", poperands);
  1330.       break;
  1331.     case DFmode:
  1332.       output_move_double (poperands);
  1333.       break;
  1334.     case XFmode:
  1335.       output_move_extended (poperands);
  1336.       break;
  1337.     default:
  1338.       abort();
  1339.     }
  1340. }
  1341.  
  1342. /* Issue the basic SANE calling sequence; push addresses of operands (which
  1343.    must already be in memory), push the op code, then trap.  The trap
  1344.    will pop everything itself, so no cleanup needed. */
  1345.  
  1346. output_sane_op (moperands, numopnds, op, name)
  1347.      rtx *moperands;
  1348.      int numopnds, op;
  1349.      char *name;
  1350. {
  1351.   char tmpbuf[100];
  1352.  
  1353.   if (numopnds > 1) 
  1354.     output_asm_insn ("pea %1", moperands);
  1355.   if (numopnds > 0)
  1356.     output_asm_insn ("pea %0", moperands);
  1357.   sprintf (tmpbuf, "move.w #$%x,-(sp)  ; %s", op, name);
  1358.   output_asm_insn (tmpbuf, NULL);
  1359.   output_asm_insn ("dc.w   $a9eb         ; FP68K", NULL);
  1360. }
  1361.  
  1362. /* Return a REG that occurs in ADDR with coefficient 1.
  1363.    ADDR can be effectively incremented by incrementing REG.  */
  1364.  
  1365. static rtx
  1366. find_addr_reg (addr)
  1367.      rtx addr;
  1368. {
  1369.   while (GET_CODE (addr) == PLUS)
  1370.     {
  1371.       if (GET_CODE (XEXP (addr, 0)) == REG)
  1372.     addr = XEXP (addr, 0);
  1373.       else if (GET_CODE (XEXP (addr, 1)) == REG)
  1374.     addr = XEXP (addr, 1);
  1375.       else if (CONSTANT_P (XEXP (addr, 0)))
  1376.     addr = XEXP (addr, 1);
  1377.       else if (CONSTANT_P (XEXP (addr, 1)))
  1378.     addr = XEXP (addr, 0);
  1379.       else
  1380.     abort ();
  1381.     }
  1382.   if (GET_CODE (addr) == REG)
  1383.     return addr;
  1384.   abort ();
  1385. }
  1386.  
  1387. char *
  1388. output_move_const_long_double (operands)
  1389.      rtx *operands;
  1390. {
  1391.     {
  1392.       int code = standard_68881_constant_p (operands[1]);
  1393.  
  1394.       if (code != 0)
  1395.     {
  1396.       static char buf[40];
  1397.  
  1398.       sprintf (buf, "fmovecr #$%x,%%0", code & 0xff);
  1399.       return buf;
  1400.     }
  1401.       return "fmove.x %1,%0";
  1402.     }
  1403. }
  1404.  
  1405. char *
  1406. output_move_const_double (operands)
  1407.      rtx *operands;
  1408. {
  1409.     {
  1410.       int code = standard_68881_constant_p (operands[1]);
  1411.  
  1412.       if (code != 0)
  1413.     {
  1414.       static char buf[40];
  1415.  
  1416.       sprintf (buf, "fmovecr #$%x,%%0", code & 0xff);
  1417.       return buf;
  1418.     }
  1419.       return "fmove.d %1,%0";
  1420.     }
  1421. }
  1422.  
  1423. char *
  1424. output_move_const_single (operands)
  1425.      rtx *operands;
  1426. {
  1427.     {
  1428.       int code = standard_68881_constant_p (operands[1]);
  1429.  
  1430.       if (code != 0)
  1431.     {
  1432.       static char buf[40];
  1433.  
  1434.       sprintf (buf, "fmovecr #$%x,%%0", code & 0xff);
  1435.       return buf;
  1436.     }
  1437.       return "fmove.s %1,%0";
  1438.     }
  1439. }
  1440.  
  1441. /* Return nonzero if X, a CONST_DOUBLE, has a value that we can get
  1442.    from the "fmovecr" instruction.
  1443.    The value, anded with 0xff, gives the code to use in fmovecr
  1444.    to get the desired constant.  */
  1445.  
  1446. /* This seems dubious for MPW... */
  1447.  
  1448. int
  1449. standard_68881_constant_p (x)
  1450.      rtx x;
  1451. {
  1452.   union {double d; int i[2];} u;
  1453.   register double d;
  1454.   u.i[0] = CONST_DOUBLE_LOW (x);
  1455.   u.i[1] = CONST_DOUBLE_HIGH (x);
  1456.   d = u.d;
  1457.  
  1458.   if (d == 0)
  1459.     return 0x0f;
  1460.   /* Note: there are various other constants available
  1461.      but it is a nuisance to put in their values here.  */
  1462.   if (d == 1)
  1463.     return 0x32;
  1464.   if (d == 10)
  1465.     return 0x33;
  1466.   if (d == 100)
  1467.     return 0x34;
  1468.   if (d == 10000)
  1469.     return 0x35;
  1470.   if (d == 1e8)
  1471.     return 0x36;
  1472.   if (GET_MODE (x) == SFmode)
  1473.     return 0;
  1474.   if (d == 1e16)
  1475.     return 0x37;
  1476.   /* larger powers of ten in the constants ram are not used
  1477.      because they are not equal to a `double' C constant.  */
  1478.   return 0;
  1479. }
  1480.  
  1481. /* Print out a string in MPW Asm-approved syntax.  Main trickiness is
  1482.    to recognize non-printing characters and put them out as raw bytes,
  1483.    while keeping as many printable characters in a string as possible
  1484.    (saves space in asm code and makes it more readable too). */
  1485.  
  1486. /* newline/cr character mapping was handled at lex time... */
  1487.  
  1488. output_mpw_string(fp, str, size)
  1489. FILE *fp;
  1490. char *str;
  1491. int size;
  1492. {
  1493.     char ch;
  1494.     int i;
  1495.  
  1496.     fprintf(fp, "\tDC.B '");
  1497.     for (i = 0; i < size; ++i)
  1498.       {
  1499.     ch = str[i];
  1500.     if (ch == '\'')
  1501.       {
  1502.         fprintf(fp, "''");
  1503.       }
  1504.     else if ((ch >= '\0' && ch < ' ') || (ch > '~'))
  1505.       {
  1506.         fprintf(fp, "'\n\tDC.B %d\n\tDC.B '", ch);
  1507.       }
  1508.     else if (i > 0 && i % 60 == 0)
  1509.       {
  1510.         fprintf (fp, "%c'\n\tDC.B '", ch);
  1511.       }
  1512.     else
  1513.       {
  1514.         fprintf(fp, "%c", ch);
  1515.       }
  1516.       }
  1517.     fprintf(fp, "'\n");
  1518.   /* Ending NUL char is part of the string's "size", so doesn't need to be added. */
  1519. }
  1520.  
  1521. /* Print out a floating rtx in some useful way. */
  1522.  
  1523. #include "real.h"
  1524.  
  1525. output_mpw_float (fp, x)
  1526. FILE *fp;
  1527. rtx x;
  1528. {
  1529.   union { REAL_VALUE_TYPE f; int i[3]; } u;
  1530.   double d;
  1531.   float f;
  1532.  
  1533.   u.i[0] = CONST_DOUBLE_LOW (x);
  1534.   u.i[1] = CONST_DOUBLE_HIGH (x);
  1535.   u.i[2] = CONST_DOUBLE_TOP (x);
  1536.  
  1537.   switch (GET_MODE (x))
  1538.     {
  1539.     case SFmode:
  1540.       f = u.f;
  1541.       fprintf (fp, "\"%.9g\"", f);
  1542.       break;
  1543.     case DFmode:
  1544.       d = u.f;
  1545.       fprintf (fp, "\"%.20g\"", d);
  1546.       break;
  1547.     case XFmode:
  1548.       fprintf (fp, "\"%.30g\"", u.f);
  1549.       break;
  1550.     default:
  1551.       abort ();
  1552.     }
  1553. }
  1554.  
  1555. output_mpw_float_as_int (fp, x)
  1556. FILE *fp;
  1557. rtx x;
  1558. {
  1559.   union { REAL_VALUE_TYPE f; int i[3]; } u;
  1560.   union { float f; int i[1]; } u2;
  1561.  
  1562.   u.i[0] = CONST_DOUBLE_LOW (x);
  1563.   u.i[1] = CONST_DOUBLE_HIGH (x);
  1564.   u.i[2] = CONST_DOUBLE_TOP (x);
  1565.  
  1566.   u2.f = u.f;
  1567.  
  1568.   switch (GET_MODE (x))
  1569.     {
  1570.     case SFmode:
  1571.       fprintf (fp, "%d", u2.i[0]);
  1572.       break;
  1573.     case DFmode:
  1574.     case XFmode:
  1575.       fprintf (stderr, "Can't integerize a double or extended const!\n");
  1576.     default:
  1577.       abort ();
  1578.     }
  1579. }
  1580.  
  1581. /* Printing extended floats is a little tricky, since both the compiler and
  1582.    the target machines care about the 10/12-byte size. */
  1583.  
  1584. output_mpw_long_double (fp, x)
  1585. FILE *fp;
  1586. REAL_VALUE_TYPE x;
  1587. {
  1588.   union { REAL_VALUE_TYPE f; short s[6]; } u;
  1589.   int a = 0;
  1590.  
  1591.   u.f = x;
  1592.  
  1593.   fprintf (fp, "\tDC.W %d,", u.s[0]);
  1594.   if (TARGET_68881)
  1595.     {
  1596. #ifdef mc68881
  1597.       fprintf (fp, "%d,", u.s[1]);
  1598.       a = 1;
  1599. #else
  1600.       fprintf (fp, "0,");
  1601.       a = 0;
  1602. #endif
  1603.     }
  1604.   fprintf (fp, "%d,%d,%d,%d  ; %.30g\n",
  1605.        u.s[a+1], u.s[a+2], u.s[a+3], u.s[a+4], x);
  1606. }
  1607.  
  1608. /* We need to recognize all possible references to global data.  */
  1609.  
  1610. global_data_ref_p (addr)
  1611.     rtx addr;
  1612. {
  1613.   switch (GET_CODE (addr))
  1614.     {
  1615.     case SYMBOL_REF:
  1616.       {
  1617.     char *name = XSTR (addr, 0);
  1618.  
  1619.     return (name[0] == '2');
  1620.       }
  1621.     case PLUS:
  1622.       return (global_data_ref_p (XEXP (addr, 0))
  1623.           || global_data_ref_p (XEXP (addr, 1)));
  1624.     case CONST:
  1625.       return global_data_ref_p (XEXP (addr, 0));
  1626.     default:
  1627.       return 0;
  1628.     }
  1629.   return 0;
  1630. }
  1631.  
  1632. /* Test a string to see if it matches any register names.  A few extra
  1633.    tests on individual chars to optimize - a more serious approach would
  1634.    involve a binary search tree or something.  Don't bother unless this
  1635.    can be proved to take significant time!  */
  1636.  
  1637. /* Names not in the regular reg_names list that the assembler knows about
  1638.    and will choke on if you attempt to use them as labels.  */
  1639.  
  1640. char *obscure_reg_names[] = {
  1641.   "sp",
  1642.   "a7",
  1643.   "za7",
  1644.   "pc",
  1645.   "zpc",
  1646.   "ccr",
  1647.   "sr",
  1648.   "usp",
  1649.   "sfc",
  1650.   "dfc",
  1651.   "cacr",
  1652.   "vbr",
  1653.   "caar",
  1654.   "msp",
  1655.   "isp",
  1656.   NULL };
  1657.   
  1658. mpw_register_name (str)
  1659. char *str;
  1660. {
  1661.   int i;
  1662.   extern char* reg_names[];
  1663.  
  1664.   if (str[0] == 'd' || str[0] == 'a' || str[0] == 'f')
  1665.     {
  1666.       for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i)
  1667.     if (strcmp (str, reg_names[i]) == 0)
  1668.       return 1;
  1669.     }
  1670.   if (str[0] == 'z' && (str[1] == 'd' || str[1] == 'a'))
  1671.     {
  1672.       for (i = 0; i < FIRST_PSEUDO_REGISTER; ++i)
  1673.     if (strcmp (str, reg_names[i]+1) == 0)
  1674.       return 1;
  1675.     }
  1676.   /* There are other more obscure register names to test as well. */
  1677.   for (i = 0; obscure_reg_names[i]; ++i)
  1678.     if (strcmp (str, obscure_reg_names[i]) == 0)
  1679.       return 1;
  1680.   return 0;
  1681. }
  1682.  
  1683. char *
  1684. avoid_mpw_register_name (name)
  1685.      char *name;
  1686. {
  1687.   int typechar = ('0' <= name[0] && name[0] <= '9');
  1688.   char *newname = name;
  1689.  
  1690.   if (mpw_register_name (name + typechar))
  1691.     {
  1692.       /* should warn that name is being changed. */
  1693.       newname = (char *) xmalloc (strlen (name) + 2);
  1694.       strcpy (newname, name);
  1695.       strcat (newname, "_");
  1696.       warning ("`%s' is a register name; changing to `%s'",
  1697.            name + typechar, newname + typechar);
  1698.     }
  1699.   return newname;
  1700. }
  1701.  
  1702. /* Implementing -b requires saving up strings somewhere. */
  1703.  
  1704. char *lbls[100];
  1705. char *strs[100];
  1706. int lsix = 0;
  1707. int totlen = 0;
  1708.  
  1709. record_a_string(lbl, str)
  1710. char *lbl, *str;
  1711. {
  1712.   if (lsix >= 99) abort ();
  1713.   lbls[lsix] = lbl;
  1714.   strs[lsix] = str;
  1715.   totlen += strlen(str) + 1;
  1716.   totlen += (totlen & 1);   /* keeps it aligned */
  1717.   lsix++;
  1718. }
  1719.  
  1720. /* Functions compiled with -b have all their strings at the end of the
  1721.    function, preceded by a length field. */
  1722.  
  1723. /* Should scan a linked list of strings saved up for this function,
  1724.    not a fixed-size array. */
  1725.  
  1726. dump_local_strings (fp)
  1727. FILE *fp;
  1728. {
  1729.   int i;
  1730.  
  1731.   /* Only really need the length word for debugging, otherwise skip it. */
  1732.   if (TARGET_MACSBUG)
  1733.     fprintf (fp, "\tDC.W %d\n", totlen);
  1734.   for (i = 0; i < lsix; ++i)
  1735.     {
  1736.       /* String might be referred to from elsewhere within this file. */
  1737.       fprintf (fp, "\tENTRY ");
  1738.       assemble_name (fp, lbls[i]);
  1739.       fprintf (fp, "\n");
  1740.       assemble_name (fp, lbls[i]);
  1741.       output_mpw_string (fp, strs[i], strlen(strs[i])+1);
  1742.       fprintf (fp, "\tALIGN\n");
  1743.     }
  1744.   lsix = totlen = 0;
  1745. }
  1746.